﻿using System;
using System.Collections;
using System.ComponentModel;
using System.Linq;
using System.Windows;
using System.Windows.Media;

namespace Charts
{
	public class LineGraph : RangeItemsControl
	{
		
		#region DependencyProperties
		public static readonly DependencyProperty PointsProperty =
			DependencyProperty<LineGraph>.Register(x => x.Points);
		
		/// <summary>All drawings base on this set of points</summary>
		public PointCollection Points
		{
			get { return (PointCollection)GetValue(PointsProperty); }
			set { SetValue(PointsProperty, value); }
		}
		
		public static readonly DependencyProperty ValuesProperty =
			DependencyProperty<LineGraph>.Register(x => x.Values);
		
		/// <summary>For internal use, represent a set of values to show in graph</summary>
		protected IList Values
		{
			get { return (IList)GetValue(ValuesProperty); }
			set { SetValue(ValuesProperty, value); }
		}
		
		public static readonly DependencyProperty ValuePathProperty =
			DependencyProperty<LineGraph>.Register(x => x.ValuePath, x => e => {
			                                       	x.DisplayMemberPath = e.NewValue.Path;//if you don't use template selector
			                                       	x.RefreshValues();
			                                       });
		
		/// <summary>Define a property name of items source element to use in chart.
		/// Set DisplayMemberPath and change ValuePath property call RefreshValues()</summary>
		public PropertyPath ValuePath
		{
			get { return (PropertyPath)GetValue(ValuePathProperty); }
			set { SetValue(ValuePathProperty, value); }
		}
		#endregion
		
		public LineGraph() : base()
		{
			//default style control apply
			this.DefaultStyleKey = typeof(LineGraph);
		}
		
		#region Notifying ItemsSource element property changed
		protected override void OnItemsSourceChanged(System.Collections.IEnumerable oldValue, System.Collections.IEnumerable newValue)
		{
			base.OnItemsSourceChanged(oldValue, newValue);
			
			//unsubscribe
			try {
				foreach (INotifyPropertyChanged element in oldValue.Cast<INotifyPropertyChanged>())
					element.PropertyChanged -= Element_PropertyChanged;
			} catch (Exception) { }
			
			//subscribe
			try {
				foreach (INotifyPropertyChanged element in newValue.Cast<INotifyPropertyChanged>())
					element.PropertyChanged += Element_PropertyChanged;
			} catch (Exception) { }
			
			//call values refresh
			RefreshValues();
		}
		
		/// <summary>ItemsSource element property changed notifying</summary>
		protected void Element_PropertyChanged(object sender, PropertyChangedEventArgs args)
		{
			if (args.PropertyName == ValuePath.Path)
				RefreshValues();
		}
		#endregion

		/// <summary>Refresh set of values from ItemsSource using ValuePath property</summary>
		public void RefreshValues()
		{
			try {
				
				string pn = ValuePath.Path;
				Values = ItemsSource.Cast<object>().Select(e => e.GetType().GetProperty(pn).GetValue(e, null)).ToList();
				
			} catch (Exception) { }
		}
	}
}